﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using EuroManager.Domain.Simulator.AI;
using EuroManager.Domain.Simulator.Engine;

namespace EuroManager.Domain.Simulator.World
{
    [ContractClass(typeof(PlayerContract))]
    public interface IPlayer : IMovingEntity
    {
        IPlayerAI AI { get; set; }

        ITeam Team { get; }
        
        int Number { get; }
        
        PitchSide Side { get; }

        ITeam Opponent { get; }
        
        bool HasBall { get; }
        
        bool CanReachBall { get; }
        
        float TimeToReachBall { get; }
        
        Vector2D TacticalLocation { get; }

        float DistanceToOpponentGoal { get; }

        bool IsFacingOpponentGoal { get; }

        IEnumerable<IPlayer> VisiblePlayersFromOwnTeam { get; }
        
        void Run(Vector2D destination, float tolerance);
        
        void TurnToBall();

        void RunToBall();
        
        void TrapBall();

        void Observe();
        
        void ChaseBall();
        
        void ControlBall();
        
        void PushBallForward();

        void PassBall(IPlayer player);

        void Shoot();
    }

    [ContractClassFor(typeof(IPlayer))]
    public abstract class PlayerContract : IPlayer
    {
        public abstract IPlayerAI AI { get; set; }

        public abstract ITeam Team { get; }

        public abstract int Number { get; }

        public abstract PitchSide Side { get; }

        public abstract ITeam Opponent { get; }

        public abstract bool HasBall { get; }

        public abstract bool CanReachBall { get; }

        public abstract float TimeToReachBall { get; }

        public abstract Vector2D TacticalLocation { get; }

        public abstract float DistanceToOpponentGoal { get; }

        public abstract bool IsFacingOpponentGoal { get; }

        public abstract IEnumerable<IPlayer> VisiblePlayersFromOwnTeam { get; }

        public abstract Vector2D Location { get; }

        public abstract float X { get; }

        public abstract float Y { get; }

        public abstract Vector2D Velocity { get; }

        public abstract Vector2D Heading { get; }

        public abstract bool IsMoving { get; }

        public abstract float Speed { get; }

        public void Observe()
        {
            Contract.Requires(AI != null);
        }

        public void ChaseBall()
        {
            Contract.Requires(AI != null);
        }

        public void ControlBall()
        {
            Contract.Requires(AI != null);
        }

        public abstract void Run(Vector2D destination, float tolerance);

        public abstract void TurnToBall();

        public abstract void RunToBall();

        public abstract void TrapBall();

        public abstract void PushBallForward();

        public void PassBall(IPlayer player)
        {
            Contract.Requires(player != null);
        }

        public abstract void Shoot();

        public abstract float DistanceTo(Vector2D target);

        public abstract float DistanceTo(IMovingEntity entity);

        public abstract Vector2D DirectionTo(Vector2D target);

        public abstract Vector2D DirectionTo(IMovingEntity entity);

        public abstract void Turn(Vector2D target);

        public abstract void Update(float elapsedTime);
    }
}
